{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# §4: Application of N-dim array\n",
    "\n",
    "## 4.1  Linear algbra\n",
    "\n",
    "### Scalar function\n",
    "\n",
    "linalg.norm(x, ord=None, axis=None, keepdims=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.7416573867739413\n",
      "6.0 3.0\n",
      "[[ 1. -2.]\n",
      " [-2.  5.]]\n",
      "7.0 7.0 5.830951894845301 5.828427124746191\n",
      "[[3. 7.]]\n",
      "[3. 7.]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import numpy.linalg as LA\n",
    "\n",
    "\n",
    "d = np.array([1,-2,3], dtype='float')\n",
    "print(LA.norm(d))\n",
    "print(LA.norm(d,1), LA.norm(d, np.inf))\n",
    "\n",
    "A = np.array([[1,-2],[-2,5]], dtype='float')\n",
    "print(A)\n",
    "print(LA.norm(A, 1), LA.norm(A, np.inf), LA.norm(A, 'fro'), LA.norm(A, 2))\n",
    "print(LA.norm(A, 1, axis=0, keepdims=True))\n",
    "print(LA.norm(A, 1, axis=0, keepdims=False))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "trace: 6.0\n",
      "determinant: -1.0000000000000004\n",
      "rank: 2\n",
      "condition number: 38.999999999999986\n"
     ]
    }
   ],
   "source": [
    "print('trace:', A.trace())\n",
    "print('determinant:', LA.det(A))\n",
    "print('rank:', LA.matrix_rank(A))\n",
    "print('condition number:', LA.cond(A, 'fro'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Eigenvalues"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "eigen values: [0.17157288 5.82842712]\n",
      "eigen vectors: [[-0.92387953  0.38268343]\n",
      " [-0.38268343 -0.92387953]]\n",
      "(array([0.17157288, 5.82842712]), array([[-0.92387953, -0.38268343],\n",
      "       [-0.38268343,  0.92387953]]))\n"
     ]
    }
   ],
   "source": [
    "eigvalues, eigvectors = LA.eig(A)\n",
    "print('eigen values:',eigvalues)\n",
    "print('eigen vectors:',eigvectors)\n",
    "\n",
    "#Return the eigenvalues and eigenvectors of a complex Hermitian (conjugate symmetric) \n",
    "#or a real symmetric matrix\n",
    "print(LA.eigh(A))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Solving equations and inverting matrices"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "solution： [2. 1.]\n",
      "inverse:  [[5. 2.]\n",
      " [2. 1.]]\n",
      "[[1. 2.]\n",
      " [3. 4.]\n",
      " [5. 6.]]\n",
      "Moore-Penrose pseudo-inverse:  [[-1.33333333 -0.33333333  0.66666667]\n",
      " [ 1.08333333  0.33333333 -0.41666667]]\n",
      "[-1.33333333  1.08333333] [0.16666667] 2 [9.52551809 0.51430058]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\ProgramData\\Anaconda3\\lib\\site-packages\\ipykernel_launcher.py:9: FutureWarning: `rcond` parameter will change to the default of machine precision times ``max(M, N)`` where M and N are the input matrix dimensions.\n",
      "To use the future default and silence this warning we advise to pass `rcond=None`, to keep using the old, explicitly pass `rcond=-1`.\n",
      "  if __name__ == '__main__':\n"
     ]
    }
   ],
   "source": [
    "b = np.array([0,1.])\n",
    "print('solution：', LA.solve(A,b))\n",
    "print('inverse: ', LA.inv(A))\n",
    "\n",
    "D = np.array([[1,2], [3,4], [5,6]], dtype='float')\n",
    "print(D)\n",
    "print('Moore-Penrose pseudo-inverse: ', LA.pinv(D))\n",
    "#least-squares solution\n",
    "x, res, r, s = LA.lstsq(D, np.array([1,0,0]))\n",
    "print(x, res, r, s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Decompose"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "QR decompose:\n",
      "[[-0.4472136   0.89442719]\n",
      " [ 0.89442719  0.4472136 ]]\n",
      "[[-2.23606798  5.36656315]\n",
      " [ 0.          0.4472136 ]]\n",
      "cholesky decompose:\n",
      "[[ 1.  0.]\n",
      " [-2.  1.]]\n",
      "[[ 1. -2.]\n",
      " [-2.  5.]]\n",
      "single value decompose:\n",
      "[[-0.3863177  -0.92236578]\n",
      " [-0.92236578  0.3863177 ]]\n",
      "[9.508032   0.77286964]\n",
      "[[-0.42866713 -0.56630692 -0.7039467 ]\n",
      " [ 0.80596391  0.11238241 -0.58119908]\n",
      " [ 0.40824829 -0.81649658  0.40824829]]\n"
     ]
    }
   ],
   "source": [
    "print('QR decompose:')\n",
    "Q, R = LA.qr(A)\n",
    "print(Q)\n",
    "print(R)\n",
    "\n",
    "print('cholesky decompose:')\n",
    "L = LA.cholesky(A)\n",
    "print(L)\n",
    "print(L@L.T)\n",
    "\n",
    "print('single value decompose:')\n",
    "B = np.array([[1,2,3],[4,5,6]], dtype='float')\n",
    "u,s,vt = LA.svd(B)\n",
    "print(u)\n",
    "print(s)\n",
    "print(vt)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### diagonal"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1. 0. 0.]\n",
      " [0. 2. 0.]\n",
      " [0. 0. 3.]]\n",
      "[1. 4.]\n",
      "(array([0, 1]), array([0, 1]))\n",
      "[[-1. -2.]\n",
      " [-3. -1.]]\n"
     ]
    }
   ],
   "source": [
    "print(np.diag(d))\n",
    "print(np.diag(A))\n",
    "\n",
    "diag = np.diag_indices_from(A)\n",
    "print(diag)\n",
    "A[diag] = -1\n",
    "print(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.2 matlib module"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'numpy.matrix'>\n",
      "inverse: [[5. 2.]\n",
      " [2. 1.]]\n",
      "[[5 7]\n",
      " [6 8]]\n",
      "matrix multiply:\n",
      "[[-7. -9.]\n",
      " [20. 26.]]\n",
      "slice [-2.  5.]\n",
      "Identity matrix:\n",
      "[[1 0 0]\n",
      " [0 1 0]\n",
      " [0 0 1]]\n",
      "[[0. 0. 0.]\n",
      " [0. 0. 0.]]\n",
      "[[0. 0.]]\n"
     ]
    }
   ],
   "source": [
    "import numpy.matlib\n",
    "\n",
    "\n",
    "#class matrix is inherited from 2D-array\n",
    "M = np.mat(A)\n",
    "print(type(M))\n",
    "print('inverse:', M.I)\n",
    "X = np.matrix('5 6; 7 8').T\n",
    "print(X)\n",
    "print('matrix multiply:')\n",
    "print(A*X)\n",
    "print('slice', A[:,1]) #different with array, here the result of slice is still matrix\n",
    "print('Identity matrix:')\n",
    "print(numpy.matlib.identity(3,dtype=int))\n",
    "\n",
    "print(np.matlib.zeros((2,3)))\n",
    "#If shape has length one i.e. (N,), or is a scalar N, out becomes a single row matrix of shape (1,N).\n",
    "print(np.matlib.zeros(2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.3 Sparse matrix\n",
    "\n",
    "The Sparse Matrix contains the elements where most of the elements are zero.\n",
    "\n",
    "Sparse matrices are memory efficient data structures that enable us store large matrices with very few \n",
    "\n",
    "non-zero elements aka sparse matrices. In addition to efficient storage, sparse matrix data structure \n",
    "\n",
    "also allows us to perform complex matrix computations. The ability to do such computations is \n",
    "\n",
    "incredibly powerful in a variety of data science problems. Learning to work with Sparse matrix, a large \n",
    "\n",
    "matrix or 2d-array with a lot elements being zero, can be extremely handy.\n",
    "\n",
    "Python’s SciPy library has a lot of options for creating, storing, and operating with Sparse matrices. There are 7 different types of sparse matrices available.\n",
    "\n",
    "    bsr_matrix: Block Sparse Row matrix\n",
    "    coo_matrix: COOrdinate format matrix\n",
    "    csc_matrix: Compressed Sparse Column matrix\n",
    "    csr_matrix: Compressed Sparse Row matrix\n",
    "    dia_matrix: Sparse matrix with DIAgonal storage\n",
    "    dok_matrix: Dictionary Of Keys based sparse matrix.\n",
    "    lil_matrix: Row-based linked list sparse matrix\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "create coo_matrix by ordinary array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0 1 0]\n",
      " [0 0 2]\n",
      " [3 0 0]]\n",
      "[0 1 2]\n",
      "[1 2 0]\n",
      "[1 2 3]\n",
      "3\n",
      "[[0 1 0]\n",
      " [0 0 2]\n",
      " [3 0 0]]\n"
     ]
    }
   ],
   "source": [
    "import scipy.sparse as sp\n",
    "\n",
    "a = np.array([[0,1,0], [0,0,2], [3,0,0]])\n",
    "print(a)\n",
    "m_coo = sp.coo_matrix(a)\n",
    "print(m_coo.row)\n",
    "print(m_coo.col)\n",
    "print(m_coo.data)\n",
    "print(m_coo.nnz) #number of non-zero element\n",
    "print(m_coo.todense()) #transform to ordinary matrix"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "create coo_matrix by (row, col, data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  (0, 0)\t4\n",
      "  (3, 3)\t5\n",
      "  (1, 1)\t7\n",
      "  (0, 2)\t9\n",
      "[[4 0 9 0]\n",
      " [0 7 0 0]\n",
      " [0 0 0 0]\n",
      " [0 0 0 5]]\n"
     ]
    }
   ],
   "source": [
    "row  = np.array([0, 3, 1, 0])\n",
    "col  = np.array([0, 3, 1, 2])\n",
    "data = np.array([4, 5, 7, 9])\n",
    "m_coo2 = sp.coo_matrix((data, (row, col)), shape=(4, 4))\n",
    "print(m_coo2)\n",
    "print(m_coo2.toarray())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "CSR matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0 2 1 3]\n",
      "[0 2 3 3 4]\n"
     ]
    }
   ],
   "source": [
    "m_csr = m_coo2.tocsr()\n",
    "print(m_csr.indices) #column indices\n",
    "print(m_csr.indptr) #how many elements of each row"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "scipy.sparse.rand(m, n, density=0.01, format='coo', dtype=None, random_state=None)\n",
    "    \n",
    "    m,n: It defines the shape of matrix-like we want to build a matrix of shape 2 by 3 where m and n are 2 and 3 respectively.\n",
    "    density: It is used to specify the density of the matrix that we want to generate, if we specify the density of the matrix as 1, then it is the full matrix. If specify density as 0 which means the matrix contains no non-zero items.\n",
    "    format: It is used to specify the format of the matrix.\n",
    "    dtype: It is used to define the data type of the returned matrix values.\n",
    "    random_state: It is used to generate the reproducible values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  (2, 1)\t0.018094609927647665\n",
      "  (3, 0)\t0.8178337647246168\n",
      "[[0.         0.         0.        ]\n",
      " [0.         0.         0.        ]\n",
      " [0.         0.01809461 0.        ]\n",
      " [0.81783376 0.         0.        ]]\n"
     ]
    }
   ],
   "source": [
    "from scipy.sparse import rand\n",
    "\n",
    "m_rand = rand(4, 3, density=0.2, format=\"csr\")\n",
    "print(m_rand)\n",
    "print(m_rand.todense())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Homework\n",
    "\n",
    "1. linear equation system Ax=b is\n",
    "$$\\left\\{\n",
    "\\begin{matrix}\n",
    " x_1 - 2x_2 + x_3 = 0\\\\\n",
    " 2x_2 - 8 x_3=8\\\\\n",
    " -4x_1+5x_2+9x_3=-9\n",
    "\\end{matrix}\n",
    "\\right.\n",
    "$$\n",
    "calculate the 2-norm of vector b and the determinant, inverse matrix, and rank of matrix A, and solve the linear equation system Ax=b, where x is an unknown vector.\n",
    "\n",
    "2. Using the given matrix A=np.array ([[3, 1, 2], [2, 3, 4], [1, 2, 3]], dtype='float '), calculate the eigenvalues, eigenvectors, and condition numbers of matrix A.\n",
    "\n",
    "3. Given matrix B=np.array ([1, 2, 3], [4, 5, 6]], dtype='float '), calculate the singular value decomposition (SVD) of matrix B and the Moore Penrose pseudoinverse of matrix B.\n",
    "\n",
    "4. Given matrix C=np.array ([10, 20, 30], [40, 50, 60], [70, 80, 90]], dtype='float '), calculate the trace of matrix C, extract the 2x2 submatrix in the upper right corner of matrix C, and set the second column of matrix C to 0.\n",
    "\n",
    "5. Create a sparse matrix [[0, 0, 3, 0], [1, 0, 0, 0], [0, 2, 0, 0], [0, 0, 0, 4]], and complete the following operations:\n",
    "\n",
    "(1) Convert the sparse matrix into a COO format sparse matrix, and output its row coordinates, column coordinates, data values, and the number of non zero elements.\n",
    "\n",
    "(2) Convert the sparse matrix in COO format to a sparse matrix in CSR format, and output its column index and the number of elements per row.\n",
    "\n",
    "(3) Generate a sparse matrix with a shape of (4, 4) randomly_ Spark_ Matrix, density set to 0.2, format in CSR, and output a dense representation of the matrix.\n",
    "\n",
    "6. Given the following COO format sparse matrix:\n",
    "\n",
    "Data=np. array ([2, 1, 3, 4])\n",
    "\n",
    "Row=np. array ([0, 1, 2, 2])\n",
    "\n",
    "Col=np. array ([1, 0, 2, 3])\n",
    "\n",
    "COO_ Matrix=sp.coo_ Matrix ((data, (row, col)), shape=(3, 4))\n",
    "\n",
    "Please complete the following actions:\n",
    "\n",
    "(1) Output the row coordinates, column coordinates, data values, and the number of non zero elements of the sparse matrix.\n",
    "\n",
    "(2) Convert the sparse matrix into a CSR format sparse matrix, and output its column index and the number of elements per row.\n",
    "\n",
    "(3) Calculate the sum of the rows and columns of the sparse matrix and output the result."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
